// sm3_demo.c
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/err.h>

// 打印十六进制
void print_hex(const char *label, const unsigned char *data, size_t len) {
    printf("%s: ", label);
    for (size_t i = 0; i < len; i++) {
        printf("%02x", data[i]);
    }
    printf("\n");
}

// 计算 SM3 摘要
int compute_sm3(const unsigned char *input, size_t input_len, unsigned char *digest) {
    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
    if (!ctx) return -1;

    int ret = 0;
    if (EVP_DigestInit_ex(ctx, EVP_sm3(), NULL) != 1 ||
        EVP_DigestUpdate(ctx, input, input_len) != 1 ||
        EVP_DigestFinal_ex(ctx, digest, NULL) != 1) {
        fprintf(stderr, "SM3 digest failed\n");
        ERR_print_errors_fp(stderr);
        ret = -1;
    }

    EVP_MD_CTX_free(ctx);
    return ret;
}

// 计算 SM3-HMAC
int compute_sm3_hmac(const unsigned char *key, size_t key_len,
                     const unsigned char *input, size_t input_len,
                     unsigned char *hmac_out) {
    // 方法1：使用 HMAC() 函数（推荐，简洁）
    unsigned int hmac_len;
    if (!HMAC(EVP_sm3(), key, (int)key_len, input, input_len, hmac_out, &hmac_len)) {
        fprintf(stderr, "SM3-HMAC failed\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }
    // HMAC 长度应为 SM3 摘要长度（32 字节）
    return 0;
}

// 方法2（可选）：使用 EVP_MAC 接口（OpenSSL 3.0 新风格）
/*
int compute_sm3_hmac_evpmac(const unsigned char *key, size_t key_len,
                            const unsigned char *input, size_t input_len,
                            unsigned char *hmac_out) {
    EVP_MAC *mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
    if (!mac) return -1;

    EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(mac);
    if (!ctx) {
        EVP_MAC_free(mac);
        return -1;
    }

    OSSL_PARAM params[2];
    params[0] = OSSL_PARAM_construct_utf8_string("digest", "SM3", 0);
    params[1] = OSSL_PARAM_construct_end();

    if (EVP_MAC_init(ctx, key, key_len, params) != 1 ||
        EVP_MAC_update(ctx, input, input_len) != 1 ||
        EVP_MAC_final(ctx, hmac_out, NULL, EVP_MAX_MD_SIZE) != 1) {
        ERR_print_errors_fp(stderr);
        EVP_MAC_CTX_free(ctx);
        EVP_MAC_free(mac);
        return -1;
    }

    EVP_MAC_CTX_free(ctx);
    EVP_MAC_free(mac);
    return 0;
}
*/

int main(void) {
    const unsigned char msg[] = "Hello, SM3!";
    size_t msg_len = sizeof(msg) - 1; // 去掉 '\0'

    const unsigned char key[] = "my_secret_key";
    size_t key_len = sizeof(key) - 1;

    unsigned char sm3_digest[EVP_MAX_MD_SIZE];   // SM3 输出 32 字节
    unsigned char sm3_hmac[EVP_MAX_MD_SIZE];

    // 1. 计算 SM3 摘要
    if (compute_sm3(msg, msg_len, sm3_digest) != 0) {
        return 1;
    }
    print_hex("SM3 Digest", sm3_digest, 32);

    // 2. 计算 SM3-HMAC
    if (compute_sm3_hmac(key, key_len, msg, msg_len, sm3_hmac) != 0) {
        return 1;
    }
    print_hex("SM3-HMAC  ", sm3_hmac, 32);

    // 验证：SM3 固定测试向量（可选）
    // 示例：SM3("") = 1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b
    const unsigned char empty[] = "";
    unsigned char empty_digest[32];
    if (compute_sm3(empty, 0, empty_digest) == 0) {
        print_hex("SM3(\"\")   ", empty_digest, 32);
    }

    return 0;
}
